from typing import Any, Optional

from flow_engine.core.graph import FlowGraph
from flow_engine.execution.runner import FlowRunner
from flow_engine.execution.demo_runner import DemoRunner
try:
    from flow_engine.execution.langgraph_runner import LangGraphRunner
    HAS_LANGGRAPH = True
except Exception:
    LangGraphRunner = None  # type: ignore
    HAS_LANGGRAPH = False

from ..utils import RUNNERS


def create_runner(graph: FlowGraph, engine: str, max_steps: int, timeout: Optional[float], parallelism: Optional[int], flow_id: Optional[int] = None, run_id: Optional[int] = None) -> Any:
    if engine == 'flow':
        return FlowRunner(graph, max_steps=max_steps, node_timeout=timeout, flow_id=flow_id, run_id=run_id)
    elif engine == 'lang':
        if not HAS_LANGGRAPH:
            raise RuntimeError("LangGraph engine not available")
        return LangGraphRunner(graph, max_steps=max_steps, node_timeout=timeout, parallelism=parallelism or 1, flow_id=flow_id, run_id=run_id)  # type: ignore
    else:
        return DemoRunner(graph, max_steps=max_steps, flow_id=flow_id, run_id=run_id)


def register_runner(run_id: int, runner: Any) -> None:
    RUNNERS[run_id] = runner


def unregister_runner(run_id: int) -> None:
    RUNNERS.pop(run_id, None)


def get_runner(run_id: int) -> Optional[Any]:
    return RUNNERS.get(run_id)


def stop_run(run_id: int) -> bool:
    r = RUNNERS.get(run_id)
    if not r:
        return False
    try:
        r.request_stop()
        return True
    except Exception:
        return False
